package com.thiruvathukal.examples.dom;

/*
 * XML code examples by George K. Thiruvathukal. Unless noted otherwise
 * this code is covered by GPLv2. We are still working on the licensing
 * text and will update all code and documentation shortly.
 */

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Properties;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

import com.sun.org.apache.xerces.internal.parsers.DOMParser;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import com.thiruvathukal.examples.dom.traversal.DOMTraversal;

public class BasicParse1 {

	protected static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces";

	protected static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation";

	protected static final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema";

	protected static final String SCHEMA_FULL_CHECKING_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking";

	protected static final boolean DEFAULT_NAMESPACES = true;
	protected static final boolean DEFAULT_NAMESPACE_PREFIXES = false;
	protected static final boolean DEFAULT_VALIDATION = false;
	protected static final boolean DEFAULT_SCHEMA_VALIDATION = false;
	protected static final boolean DEFAULT_SCHEMA_FULL_CHECKING = false;
	protected static final String[] FEATURES;
	protected static final boolean[] FEATURES_ENABLED;

	static {
		FEATURES = new String[] { NAMESPACES_FEATURE_ID, VALIDATION_FEATURE_ID,
				SCHEMA_VALIDATION_FEATURE_ID, SCHEMA_FULL_CHECKING_FEATURE_ID, };
		FEATURES_ENABLED = new boolean[] { DEFAULT_NAMESPACES,
				DEFAULT_VALIDATION, DEFAULT_SCHEMA_VALIDATION,
				DEFAULT_SCHEMA_FULL_CHECKING };
	}

	/** Main program entry point. */
	public static void main(String args[]) {

		DOMParser parser = new DOMParser();

		// Check feature vectors for consistency.

		if (FEATURES.length != FEATURES_ENABLED.length) {
			System.err
					.println("FETURES and FEATURES_ENABLED must be equal length.");
			System.exit(1);
		}

		// Enable features...

		for (int featureId = 0; featureId < FEATURES.length; featureId++) {
			try {
				parser.setFeature(FEATURES[featureId],
						FEATURES_ENABLED[featureId]);
			} catch (SAXException e) {
				System.err.println("warning: Unsupported feature "
						+ FEATURES[featureId]);
			}
		}

		// Parse all files specified on command line.
		try {
			Document document = null;
			if (true) {
				parser.parse(args[0]);
				document = parser.getDocument();
				System.out.println("\n* input text " + args[0]);
				echo(document);
				DOMTraversal nt = new DOMTraversal(document);
				Count1 c = new Count1();
				nt.addVisitor(c);
				nt.visit(null);
				System.out.println("Stastics: " + c);

			} else {
				for (int fileId = 0; fileId < args.length; fileId++) {
					parser.parse(args[fileId]);
					document = parser.getDocument();
				}
			}

		} catch (Exception e) {
			System.err.println("error: Parse error occurred - "
					+ e.getMessage());
			e.printStackTrace(System.err);
		}
	}

	public static Properties getNodeProperties(Node node) {
		Properties p = new Properties();
		p.setProperty("getNodeType()", node.getNodeType() + "");
		p.setProperty("getNodeName()", node.getNodeName() + "");
		try {
			p.setProperty("getNodeValue()", node.getNodeValue() + "");
		} catch (DOMException e) {
			p.setProperty("getNodeValue()", "DOMException: " + e.code);
		}
		p.setProperty("hasChildNodes()", node.hasChildNodes() + "");
		p.setProperty("getNamespaceURI()", node.getNamespaceURI() + "");
		p.setProperty("getPrefix()", node.getPrefix() + "");
		p.setProperty("getLocalName()", node.getLocalName() + "");
		try {
			p.setProperty("hasAttributes()", node.hasAttributes() + "");
		} catch (DOMException e) {
			p.setProperty("hasAttributes()", "DOMException: " + e.code);
		}
		p.setProperty("getBaseURI()", node.hasAttributes() + "");

		// try {
		// p.setProperty("getTextContent()", node.getTextContent() + "");
		// } catch(DOMException e) {
		// p.setProperty("getTextContent()", "DOMException: " + e.code);
		// }
		try {
			p.setProperty("hasChildNodes()", node.hasChildNodes() + "");
		} catch (DOMException e) {
			p.setProperty("hasChildNodes()", "DOMException: " + e.code);
		}
		return p;
	}

	/** Traverses the specified node, recursively. */
	public static void count(Node node) {
		Properties p;
		if (node == null) {
			return;
		}

		p = getNodeProperties(node);
		int type = node.getNodeType();
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		p.list(pw);
		System.out.println("Node:");
		System.out.println(sw);
		System.out.println();

		switch (type) {
		case Node.DOCUMENT_NODE: {
			Document document = (Document) node;
			count(document.getDocumentElement());
			break;
		}

		case Node.ELEMENT_NODE: {
			NamedNodeMap attrs = node.getAttributes();
			for (int attrNo = 0; attrNo < attrs.getLength(); attrNo++)
				count(attrs.item(attrNo));
			// if (attrs != null) {
			// fAttributes += attrs.getLength();
			// }
			// drop through to entity reference
		}

		case Node.ENTITY_REFERENCE_NODE: {
			Node child = node.getFirstChild();
			while (child != null) {
				count(child);
				child = child.getNextSibling();
			}
			break;
		}

		case Node.CDATA_SECTION_NODE: {
			// fCharacters += ((Text)node).getLength();
			break;
		}

		case Node.TEXT_NODE: {
			// if (fDocumentInfo != null) {
			// Text text = (Text)node;
			// int length = text.getLength();
			// if (fDocumentInfo.isIgnorableWhitespace(text)) {
			// fIgnorableWhitespace += length;
			// }
			// else {
			// fCharacters += length;
			// }
			// }
			break;
		}
		}
	} // count(Node)

	public static void echo(Document document) {
		OutputFormat format = new OutputFormat(document, "UTF-8", true);
		StringWriter stringOut = new StringWriter();
		XMLSerializer serial = new XMLSerializer(stringOut, format);
		try {
			serial.asDOMSerializer();
			serial.serialize(document.getDocumentElement());
		} catch (Exception e) {
			System.err.println("Exception " + e);
		}
		System.out.println("XML\n---");
		System.out.println(stringOut.toString());
	}
}
